package tools;

import hitExceptions.InvalidDataException;
import hitExceptions.InvalidOperationException;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import coreModel.Barcode;
import coreModel.HIT;
import coreModel.Item;
import coreModel.Product;
import coreModel.ProductContainer;
import coreModel.ProductGroup;
import coreModel.StorageUnit;
import coreModel.Supply;
import coreModel.Unit;
import dataPersistence.TransactionManager;

/**
 * @author Fantastic 4
 * 
 * A program that loads a HIT model and creates a PDF file to represent it.
 */

public class Exporter {
	
	//static HIT theHit=HIT.getInstance(); 
	static SimpleDateFormat dfEntry, dfExit; 
	private static boolean inDBMode;
	private static boolean error;
	
	private static void print(String message) 
	{
		System.out.println(message);
	}
	
	private static void usage() {
		print("USAGE: java tools.Exporter [-sql] <data-file>");
	}

	/** Loads from file/database and performs the export.
	 * 
	 * @param args An array containing the arguments
	 */
	public static void main(String[] args) 
	{
		if (args.length < 1)
		{
			usage();
			System.exit(2);
		}
		dfEntry= new SimpleDateFormat("MM/dd/yyyy");
		dfExit= new SimpleDateFormat("MM/dd/yyyy hh:mm a");
		try
		{
			
			//set db mode
			if(args.length ==2 && args[0].equalsIgnoreCase("-sql"))
			{
				//flags for db
				inDBMode = true;
				error=false;
				System.out.println("in bd mode");
				HIT.getInstance().setDataPersistenceFactory(true);
							
				TransactionManager.begin();
			}
			else
			{
				inDBMode=false;
				System.out.println("in serial mode");
				HIT.getInstance().setDataPersistenceFactory(false);
			}
			HIT.getInstance().load("hit.db");
			//theHit=HIT.getInstance();
			
			String fileString = new String(args[args.length-1]);			
			createXML(fileString);
		} 
		catch (TransformerException e)
		{
			error =true;
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		catch (InvalidOperationException e) {
			error=true;
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally 
		{
			if(inDBMode && TransactionManager.getConnection()!=null)
				TransactionManager.end(error);
		}
	}
	
	private static void createXML(String filename) throws TransformerException
	{
		
		try
		{
			//init the tool
			DocumentBuilderFactory docFactory= DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			
			
			// root elements inventory-Tracker element
			Document doc = docBuilder.newDocument();
			
			//add base element
			Element rootElement = doc.createElement("inventory-tracker");
			doc.appendChild(rootElement);
	 
			
			// ProductElements
			Element allProducts = doc.createElement("products");
			addAllProducts(allProducts,doc);
			// add product node to root node
			rootElement.appendChild(allProducts);
	 
			// ProductElements
			Element allUnits = doc.createElement("storage-units");
			addAllStorageUnits(allUnits,doc);
			// add product node to root node
			rootElement.appendChild(allUnits);
			
			// add removed items
			Element removedItems = doc.createElement("item-history");
			addRemovedItems(removedItems,doc);
			rootElement.appendChild(removedItems);
			
				 
			// write the content into xml file
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(new File(filename));
	 
			// Output to console for testing
			// StreamResult result = new StreamResult(System.out);
	 
			transformer.transform(source, result);
	 
			System.out.println("Saved to file: " + filename);
		} 
		catch (ParserConfigurationException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally
		{
			
		}
	}

	private static void addRemovedItems(Element removedItems, Document doc) 
	{
		Collection<Item> items = HIT.getInstance().getItemHistory().getAllItems();
		
		for(Item i: items)
		{
			//System.out.println(i);
			Element tmpItem = doc.createElement("item");
			
			Attr prodAttr = doc.createAttribute("product");
			prodAttr.setValue(i.getProduct().getBarcode().toString());
			
			Attr entryDate = doc.createAttribute("entry-date");
			entryDate.setValue(dfEntry.format(i.getEntryDate()));
			
			Attr exitTime = doc.createAttribute("exit-time");
			exitTime.setValue(dfExit.format(i.getExitTime()));
			
			tmpItem.setAttributeNode(prodAttr);
			tmpItem.setAttributeNode(entryDate);
			tmpItem.setAttributeNode(exitTime);
			
			removedItems.appendChild(tmpItem);
		}
	}

	private static void addAllStorageUnits(Element allUnits, Document doc)
	{
		Collection<StorageUnit> units = HIT.getInstance().getAllStorageUnits();
		
		for(StorageUnit p: units)
		{
			//System.out.println(p);
			Element tmpUnit= doc.createElement("storage-unit");
			Attr nameAttr = doc.createAttribute("name");
			nameAttr.setValue(p.getName());
			
			tmpUnit.setAttributeNode(nameAttr);
			allUnits.appendChild(tmpUnit);
			//create products
			
			Collection<Product> prods = HIT.getInstance().getProductManager().getProductsOfContainer(p);

			//all products adding
			Element productsElement=doc.createElement("products");
			tmpUnit.appendChild(productsElement);
			if (prods!=null)
				getProducts(prods, productsElement, doc);
			
			Collection<Item> items = HIT.getInstance().getItemManager().getAllItemsOfContainer(p);
			
			//all items adding
			Element itemsElement=doc.createElement("items");
			tmpUnit.appendChild(itemsElement);
			if(items!=null)
				getItems(items, itemsElement, doc);
			
			//all product group adding
			Element prodGroups=doc.createElement("product-groups");
			tmpUnit.appendChild(prodGroups);
			
			addAllProductGroups(prodGroups, doc, p);
		}
	}

	private static void addAllProductGroups(Element parentElement, Document doc, ProductContainer parent)
	{
		Collection<ProductGroup> pgs = parent.getProductGroups();
		
		for(ProductGroup pg: pgs)
		{
			//System.out.println(p);
			Element tmpPG = doc.createElement("product-group");
			Attr nameAttr = doc.createAttribute("name");
			nameAttr.setValue(pg.getName());
			Attr supplyAttr = doc.createAttribute("supply");
			supplyAttr.setValue(pg.getThreeMonths().toString());

			tmpPG.setAttributeNode(nameAttr);
			tmpPG.setAttributeNode(supplyAttr);
			parentElement.appendChild(tmpPG);
			//create products
			
			Collection<Product> prods = HIT.getInstance().getProductManager().getProductsOfContainer(pg);

			//all products adding
			Element productsElement=doc.createElement("products");
			tmpPG.appendChild(productsElement);
			if (prods!=null)
				getProducts(prods, productsElement, doc);
			
			Collection<Item> items = HIT.getInstance().getItemManager().getAllItemsOfContainer(pg);
			
			//all items adding
			Element itemsElement=doc.createElement("items");
			tmpPG.appendChild(itemsElement);
			if(items!=null)
				getItems(items, itemsElement, doc);
			
			//all product group adding
			Element prodGroups=doc.createElement("product-groups");
			tmpPG.appendChild(prodGroups);
			
			addAllProductGroups(prodGroups, doc, pg);
		}
	}
	
	private static void getProducts(Collection<Product>prods,Element theUnit,Document doc)
	{
		for(Product prod:prods)
		{
			Element product = doc.createElement("product");
			Attr barcodeAttr = doc.createAttribute("barcode");
			barcodeAttr.setValue(prod.getBarcode().toString());
			product.setAttributeNode(barcodeAttr);
			theUnit.appendChild(product);
		}
	}
	
	
	private static void getItems(Collection<Item> items,Element theUnit,Document doc)
	{
		for(Item item: items)
		{
			Element itemElement = doc.createElement("item");
			Attr prodAttr = doc.createAttribute("product");
			prodAttr.setValue(item.getProduct().getBarcode().toString());
			Attr entryDate = doc.createAttribute("entry-date");
			entryDate.setValue(dfEntry.format(item.getEntryDate()));
			
		
			itemElement.setAttributeNode(entryDate);
			itemElement.setAttributeNode(prodAttr);
			theUnit.appendChild(itemElement);
		}
	}

	private static void addAllProducts(Element allProducts, Document doc)
	{
		//<product barcode="041710112881" description="Crush Soda - Orange" creation-date="05/14/2011" size="67 fluid ounces" supply="6" shelf-life="0" />
		
		Collection<Product> prodList = HIT.getInstance().getProductManager().getAllProducts();
		for(Product p :prodList)
		{
			Element tmpProd= doc.createElement("product");
			allProducts.appendChild(tmpProd);
			
			//barcode attribute
			Attr attr = doc.createAttribute("barcode");
			attr.setValue(p.getBarcode().toString());
			tmpProd.setAttributeNode(attr);
			tmpProd.setAttribute("description",p.getDescription());
			
			
		
			tmpProd.setAttribute("creation-date",dfEntry.format(p.getCreationDate()));
			tmpProd.setAttribute("size",p.getSupply().toString());
			tmpProd.setAttribute("shelf-life", ""+p.getShelfLife());
			tmpProd.setAttribute("supply",""+p.getThreeMonthSupply());
			
			
			
			
			Attr desAttr = doc.createAttribute("description");
			desAttr.setValue(p.getDescription());
			tmpProd.setAttributeNode(desAttr);
			
		}
		
	}

}

